Restructure and progress towards simple compile
authorCarlhuda <carlhuda@tilde.io>
Sat, 19 Apr 2014 00:23:07 +0000 (17:23 -0700)
committerCarlhuda <carlhuda@tilde.io>
Sat, 19 Apr 2014 00:23:07 +0000 (17:23 -0700)
For now, we're going to use the operations as a library. We have some
work to do before they can transparently be used as commands, but we're
keeping an eye on making sure they remain conceptually usable over the
shell.

16 files changed:
src/bin/cargo-compile.rs
src/bin/cargo-read-manifest.rs
src/bin/cargo-rustc.rs
src/cargo/core/dependency.rs
src/cargo/core/manifest.rs
src/cargo/core/mod.rs
src/cargo/core/package.rs
src/cargo/core/source.rs [new file with mode: 0644]
src/cargo/mod.rs
src/cargo/ops/cargo_compile.rs [new file with mode: 0644]
src/cargo/ops/cargo_read_manifest.rs [new file with mode: 0644]
src/cargo/ops/cargo_rustc.rs [new file with mode: 0644]
src/cargo/ops/mod.rs [new file with mode: 0644]
src/cargo/ops/path_source.rs [new file with mode: 0644]
src/cargo/sources/mod.rs [new file with mode: 0644]
src/cargo/sources/path.rs [new file with mode: 0644]

index 91f5356394b7981c44f95ac8b2391cf0f0667bb2..9fa581a3ea8ebe029922986e39cfa21723345146 100644 (file)
@@ -1,26 +1,9 @@
 #![crate_id="cargo-compile"]
 #![allow(deprecated_owned_vector)]
 
-extern crate serialize;
-extern crate hammer;
 extern crate cargo;
 
-use std::vec::Vec;
-use serialize::{Decodable};
-use hammer::{FlagDecoder,FlagConfig,FlagConfiguration,HammerError};
-use std::io;
-use std::io::BufReader;
-use std::io::process::{Process,ProcessExit,ProcessOutput,InheritFd,ProcessConfig};
-use cargo::{ToCargoError,CargoResult};
-
-#[deriving(Decodable)]
-struct Options {
-    manifest_path: ~str
-}
-
-impl FlagConfig for Options {
-    fn config(_: Option<Options>, c: FlagConfiguration) -> FlagConfiguration { c }
-}
+use cargo::ops::cargo_compile::compile;
 
 fn main() {
     match compile() {
@@ -28,51 +11,3 @@ fn main() {
         Ok(_) => return
     }
 }
-
-fn compile() -> CargoResult<()> {
-    let options = try!(flags::<Options>());
-    let manifest_bytes = try!(read_manifest(options.manifest_path).to_cargo_error(~"Could not read manifest", 1));
-
-    call_rustc(~BufReader::new(manifest_bytes.as_slice()))
-}
-
-fn flags<T: FlagConfig + Decodable<FlagDecoder, HammerError>>() -> CargoResult<T> {
-    let mut decoder = FlagDecoder::new::<T>(std::os::args().tail());
-    Decodable::decode(&mut decoder).to_cargo_error(|e: HammerError| e.message, 1)
-}
-
-fn read_manifest(manifest_path: &str) -> CargoResult<Vec<u8>> {
-    Ok((try!(exec_with_output("cargo-read-manifest", [~"--manifest-path", manifest_path.to_owned()], None))).output)
-}
-
-fn call_rustc(mut manifest_data: ~Reader:) -> CargoResult<()> {
-    let data: &mut Reader = manifest_data;
-    try!(exec_tty("cargo-rustc", [], Some(data)));
-    Ok(())
-}
-
-fn exec_with_output(program: &str, args: &[~str], input: Option<&mut Reader>) -> CargoResult<ProcessOutput> {
-    Ok((try!(exec(program, args, input, |_| {}))).wait_with_output())
-}
-
-fn exec_tty(program: &str, args: &[~str], input: Option<&mut Reader>) -> CargoResult<ProcessExit> {
-    Ok((try!(exec(program, args, input, |config| {
-        config.stdout = InheritFd(1);
-        config.stderr = InheritFd(2);
-    }))).wait())
-}
-
-fn exec(program: &str, args: &[~str], input: Option<&mut Reader>, configurator: |&mut ProcessConfig|) -> CargoResult<Process> {
-    let mut config = ProcessConfig::new();
-    config.program = program;
-    config.args = args;
-    configurator(&mut config);
-
-    println!("Executing {} {}", program, args);
-
-    let mut process = try!(Process::configure(config).to_cargo_error(~"Could not configure process", 1));
-
-    input.map(|mut reader| io::util::copy(&mut reader, process.stdin.get_mut_ref()));
-
-    Ok(process)
-}
index ca404afb28b3eeaff05064a6c26252e012e4cd60..54ca728fb5bae8b46d8fdcee5b6d82f0cc11051b 100644 (file)
@@ -2,87 +2,10 @@
 #![allow(deprecated_owned_vector)]
 
 extern crate cargo;
-extern crate hammer;
-extern crate serialize;
-extern crate toml;
 
-use hammer::FlagConfig;
-use serialize::Decoder;
-use toml::from_toml;
-use cargo::core;
-use cargo::{CargoResult,ToCargoError,execute_main_without_stdin};
-use std::path::Path;
-
-#[deriving(Decodable,Encodable,Eq,Clone,Ord)]
-struct SerializedManifest {
-    project: ~core::Project,
-    lib: Option<~[SerializedLibTarget]>,
-    bin: Option<~[SerializedExecTarget]>
-}
-
-#[deriving(Decodable,Encodable,Eq,Clone,Ord)]
-pub struct SerializedTarget {
-    name: ~str,
-    path: Option<~str>
-}
-
-pub type SerializedLibTarget = SerializedTarget;
-pub type SerializedExecTarget = SerializedTarget;
-
-
-#[deriving(Decodable,Eq,Clone,Ord)]
-struct ReadManifestFlags {
-    manifest_path: ~str
-}
-
-impl FlagConfig for ReadManifestFlags {}
+use cargo::execute_main_without_stdin;
+use cargo::ops::cargo_read_manifest::execute;
 
 fn main() {
     execute_main_without_stdin(execute);
 }
-
-fn execute(flags: ReadManifestFlags) -> CargoResult<Option<core::Manifest>> {
-    let manifest_path = flags.manifest_path;
-    let root = try!(toml::parse_from_file(manifest_path.clone()).to_cargo_error(format!("Couldn't parse Toml file: {}", manifest_path), 1));
-
-    let toml_manifest = try!(from_toml::<SerializedManifest>(root.clone()).to_cargo_error(|e: toml::Error| format!("{}", e), 1));
-
-    let (lib, bin) = normalize(&toml_manifest.lib, &toml_manifest.bin);
-
-    Ok(Some(core::Manifest {
-        root: try!(Path::new(manifest_path.clone()).dirname_str().to_cargo_error(format!("Could not get dirname from {}", manifest_path), 1)).to_owned(),
-        project: toml_manifest.project,
-        lib: lib,
-        bin: bin
-    }))
-}
-
-fn normalize(lib: &Option<~[SerializedLibTarget]>, bin: &Option<~[SerializedExecTarget]>) -> (~[core::LibTarget], ~[core::ExecTarget]) {
-    fn lib_targets(libs: &[SerializedLibTarget]) -> ~[core::LibTarget] {
-        let l = &libs[0];
-        let path = l.path.clone().unwrap_or_else(|| format!("src/{}.rs", l.name));
-        ~[core::LibTarget { path: path, name: l.name.clone() }]
-    }
-
-    fn bin_targets(bins: &[SerializedExecTarget], default: |&SerializedExecTarget| -> ~str) -> ~[core::ExecTarget] {
-        bins.iter().map(|bin| {
-            let path = bin.path.clone().unwrap_or_else(|| default(bin));
-            core::ExecTarget { path: path, name: bin.name.clone() }
-        }).collect()
-    }
-
-    match (lib, bin) {
-        (&Some(ref libs), &Some(ref bins)) => {
-            (lib_targets(libs.as_slice()), bin_targets(bins.as_slice(), |bin| format!("src/bin/{}.rs", bin.name)))
-        },
-        (&Some(ref libs), &None) => {
-            (lib_targets(libs.as_slice()), ~[])
-        },
-        (&None, &Some(ref bins)) => {
-            (~[], bin_targets(bins.as_slice(), |bin| format!("src/{}.rs", bin.name)))
-        },
-        (&None, &None) => {
-            (~[], ~[])
-        }
-    }
-}
index 7f4304a49cbe7bf98f132dfbb3be5cc754f811cc..46977b3f8ff14ff55fa96f37f87b450fc3c52cba 100644 (file)
@@ -1,72 +1,11 @@
 #![crate_id="cargo-rustc"]
 #![allow(deprecated_owned_vector)]
 
-extern crate toml;
-extern crate hammer;
-extern crate serialize;
 extern crate cargo;
 
-use std::os::args;
-use std::io;
-use std::io::process::{Process,ProcessConfig,InheritFd};
-use std::path::Path;
-use cargo::{CargoResult,CargoError,ToCargoError,NoFlags,execute_main};
-use cargo::core;
-
-/**
-    cargo-rustc -- ...args
-
-    Delegate ...args to actual rustc command
-*/
+use cargo::execute_main;
+use cargo::ops::cargo_rustc::execute;
 
 fn main() {
     execute_main(execute);
 }
-
-fn execute(_: NoFlags, manifest: core::Manifest) -> CargoResult<Option<core::Manifest>> {
-    let core::Manifest { root, lib, bin, .. } = manifest;
-
-    let (crate_type, out_dir) = if lib.len() > 0 {
-        ( ~"lib", lib[0].path )
-    } else if bin.len() > 0 {
-        ( ~"bin", bin[0].path )
-    } else {
-        return Err(CargoError::new(~"bad manifest, no lib or bin specified", 1));
-    };
-
-    let root = Path::new(root);
-    let target = join(&root, ~"target");
-
-    let args = [
-        join(&root, out_dir),
-        ~"--out-dir", target,
-        ~"--crate-type", crate_type
-    ];
-
-    match io::fs::mkdir_recursive(&root.join("target"), io::UserRWX) {
-        Err(_) => fail!("Couldn't mkdir -p"),
-        Ok(val) => val
-    }
-
-    println!("Executing rustc {}", args.as_slice());
-
-    let mut config = ProcessConfig::new();
-    config.stdout = InheritFd(1);
-    config.stderr = InheritFd(2);
-    config.program = "rustc";
-    config.args = args.as_slice();
-
-    let mut p = try!(Process::configure(config).to_cargo_error(format!("Could not start process: rustc {}", args.as_slice()), 1));
-
-    let status = p.wait();
-
-    if status != std::io::process::ExitStatus(0) {
-        fail!("Failed to execute")
-    }
-
-    Ok(None)
-}
-
-fn join(path: &Path, part: ~str) -> ~str {
-    format!("{}", path.join(part).display())
-}
index 122a3364c0e1f4de3027fdaf2e5cf07eb68d1f8b..25a5f066ee15aa5006225d1f020634976c3ef7b5 100644 (file)
-use semver::Version;
+use core::package::NameVer;
 
-#[deriving(Clone,Eq,Show)]
+#[deriving(Eq,Clone,Show)]
 pub struct Dependency {
-    name: ~str,
-    version: Vec<VersionReq>
-}
-
-#[deriving(Clone,Eq,Show)]
-pub struct VersionReq {
-    parts: Vec<VersionOrd>
-}
-
-type VersionOrd = (Version, Vec<Ordering>);
-
-impl VersionReq {
-    pub fn parse(req: &str) -> VersionReq {
-    }
-
-    /*
-    pub fn new(version: Version, comparison: Vec<Ordering>) -> VersionReq {
-        VersionReq { comparison: comparison, version: version }
-    }
-    */
-
-    pub fn matches(&self, version: &Version) -> bool {
-        /*
-        let ordering = compare_versions(&self.version, version);
-        self.comparison.iter().any(|ord| ordering == *ord)
-        */
-        false
-    }
-}
-
-fn compare_versions(a: &Version, b: &Version) -> Ordering {
-    if a == b {
-        Equal
-    } else if a.lt(b) {
-        Less
-    } else {
-        Greater
-    }
+    name: NameVer
 }
 
 impl Dependency {
     pub fn new(name: &str) -> Dependency {
-        Dependency { name: name.to_owned(), version: Vec::new() }
+        Dependency { name: NameVer::new(name.to_owned(), "1.0.0") }
     }
 
-    pub fn get_name<'a>(&'a self) -> &'a str {
-        self.name.as_slice()
+    pub fn with_name_and_version(name: &str, version: &str) -> Dependency {
+        Dependency { name: NameVer::new(name, version) }
     }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::VersionReq;
-    use semver;
-    use semver::Version;
-    use hamcrest::{
-        assert_that,
-        Matcher,
-        MatchResult,
-        SelfDescribing
-    };
 
-    trait VersionReqExt {
-        pub fn greater_than(version: Version) -> VersionReq {
-            VersionReq::new(version, vec!(Greater))
-        }
-
-        pub fn equal_to(version: Version) -> VersionReq {
-            VersionReq::new(version, vec!(Equal))
-        }
-    }
-
-    impl VersionReqExt for VersionReq {}
-
-    #[test]
-    fn test_req_matches() {
-        let req = VersionReq::new(semver::parse("2.0.0").unwrap(), vec!(Equal));
-        //let req = greater_than(semver::parse("2.0.0").unwrap());
-
-        assert_that(req, version_match("2.0.0"));
-    }
-
-    struct VersionMatch {
-        version: ~str,
-    }
-
-    impl SelfDescribing for VersionMatch {
-        fn describe(&self) -> ~str {
-            format!("Requirement to match {}", self.version)
-        }
-    }
-
-    impl Matcher<VersionReq> for VersionMatch {
-        fn matches(&self, actual: VersionReq) -> MatchResult {
-            match semver::parse(self.version) {
-                None => Err(~"was not a valid semver version"),
-                Some(ref version) => {
-                    if actual.matches(version) {
-                        Ok(())
-                    } else {
-                        Err(format!("{} did not match {}", version, actual))
-                    }
-                }
-            }
-        }
-    }
-
-    fn version_match(str: &str) -> ~VersionMatch {
-        ~VersionMatch { version: str.to_owned() }
+    pub fn get_name<'a>(&'a self) -> &'a str {
+        self.name.get_name()
     }
-
 }
index a91ca30d99e60acef22365d1ec42261d05a0edb4..6cca1442da8829da9ec713da0579377363c1787e 100644 (file)
@@ -1,3 +1,4 @@
+use core::package::NameVer;
 
 /*
  * TODO: Make all struct fields private
@@ -8,7 +9,18 @@ pub struct Manifest {
     pub project: ~Project,
     pub root: ~str,
     pub lib: ~[LibTarget],
-    pub bin: ~[ExecTarget]
+    pub bin: ~[ExecTarget],
+    pub dependencies: Vec<NameVer>
+}
+
+impl Manifest {
+    pub fn get_name_ver(&self) -> NameVer {
+        NameVer::new(self.project.name.as_slice(), self.project.version.as_slice())
+    }
+
+    pub fn get_path<'a>(&'a self) -> Path {
+        Path::new(self.root.as_slice())
+    }
 }
 
 #[deriving(Decodable,Encodable,Eq,Clone,Ord)]
index 56b552a66cdcd2dbe8ec4a7a51f5cb9b6b89b04e..e152908a5302697f45f0c5f5045b8757b3e15a18 100644 (file)
@@ -1,19 +1,25 @@
-
-pub use self::dependency::Dependency;
 pub use self::registry::{
-  Registry,
-  MemRegistry};
+    Registry,
+    MemRegistry
+};
 
 pub use self::manifest::{
-  Manifest,
-  Project,
-  LibTarget,
-  ExecTarget};
+    Manifest,
+    Project,
+    LibTarget,
+    ExecTarget
+};
 
-pub use self::package::Package;
+pub use self::package::{
+    Package,
+    NameVer
+};
+
+pub use self::dependency::Dependency;
 
-mod dependency;
+pub mod source;
+pub mod package;
+pub mod dependency;
 mod manifest;
-mod package;
 mod registry;
 mod resolver;
index 0b9e97fa8cc7fc0b9137faa88875b1bf9dd7ce83..7ffd8bfcccee1ba84ace48c0bb49b08715211cd7 100644 (file)
@@ -1,5 +1,38 @@
 use std::vec::Vec;
+use semver;
+use semver::{Version,parse};
 use core;
+use serialize::{Encodable,Encoder,Decodable,Decoder};
+
+#[deriving(Clone,Eq,Show,Ord)]
+pub struct NameVer {
+    name: ~str,
+    version: Version
+}
+
+impl NameVer {
+    pub fn new(name: &str, version: &str) -> NameVer {
+        println!("version: {}", version);
+        NameVer { name: name.to_owned(), version: semver::parse(version.to_owned()).unwrap() }
+    }
+
+    pub fn get_name<'a>(&'a self) -> &'a str {
+        self.name.as_slice()
+    }
+}
+
+impl<E, D: Decoder<E>> Decodable<D,E> for NameVer {
+    fn decode(d: &mut D) -> Result<NameVer, E> {
+        let vector: Vec<~str> = try!(Decodable::decode(d));
+        Ok(NameVer { name: vector.get(0).clone(), version: parse(vector.get(1).clone()).unwrap() })
+    }
+}
+
+impl<E, S: Encoder<E>> Encodable<S,E> for NameVer {
+    fn encode(&self, e: &mut S) -> Result<(), E> {
+        (vec!(self.name.clone(), self.version.to_str())).encode(e)
+    }
+}
 
 /**
  * Represents a rust library internally to cargo. This will things like where
diff --git a/src/cargo/core/source.rs b/src/cargo/core/source.rs
new file mode 100644 (file)
index 0000000..e5c4fe2
--- /dev/null
@@ -0,0 +1,48 @@
+use core::package::NameVer;
+use CargoResult;
+
+pub struct PackagePath {
+    name: NameVer,
+    path: Path
+}
+
+impl PackagePath {
+    pub fn new(name: NameVer, path: Path) -> PackagePath {
+        PackagePath { name: name, path: path }
+    }
+}
+
+/**
+ * A Source finds and downloads remote packages based on names and
+ * versions.
+ */
+pub trait Source {
+    /**
+     * The update method performs any network operations required to
+     * get the entire list of all names, versions and dependencies of
+     * packages managed by the Source.
+     */
+    fn update(&self) -> CargoResult<()>;
+
+    /**
+     * The list method lists all names, versions and dependencies of
+     * packages managed by the source. It assumes that `update` has
+     * already been called and no additional network operations are
+     * required.
+     */
+    fn list(&self) -> CargoResult<Vec<NameVer>>;
+
+    /**
+     * The download method fetches the full package for each name and
+     * version specified.
+     */
+    fn download(&self, packages: Vec<NameVer>) -> CargoResult<()>;
+
+    /**
+     * The get method returns the Path of each specified package on the
+     * local file system. It assumes that `download` was already called,
+     * and that the packages are already locally available on the file
+     * system.
+     */
+    fn get(&self, packages: Vec<NameVer>) -> CargoResult<Vec<PackagePath>>;
+}
index 57947b706e87cde0829403980b3afce4d79e949c..59c284bc8124abb8b0fdd5252aeb509841a61343 100644 (file)
@@ -8,6 +8,7 @@ extern crate collections;
 extern crate hammer;
 extern crate serialize;
 extern crate semver;
+extern crate toml;
 
 #[cfg(test)]
 extern crate hamcrest;
@@ -21,6 +22,9 @@ use hammer::{FlagDecoder,FlagConfig,HammerError};
 
 pub mod core;
 pub mod util;
+pub mod sources;
+pub mod ops;
+
 
 pub type CargoResult<T> = Result<T, CargoError>;
 
diff --git a/src/cargo/ops/cargo_compile.rs b/src/cargo/ops/cargo_compile.rs
new file mode 100644 (file)
index 0000000..1da10a9
--- /dev/null
@@ -0,0 +1,82 @@
+/**
+ * Cargo compile currently does the following steps:
+ *
+ * All configurations are already injected as environment variables via the main cargo command
+ *
+ * 1. Read the manifest
+ * 2. Shell out to `cargo-resolve` with a list of dependencies and sources as stdin
+ *    a. Shell out to `--do update` and `--do list` for each source
+ *    b. Resolve dependencies and return a list of name/version/source
+ * 3. Shell out to `--do download` for each source
+ * 4. Shell out to `--do get` for each source, and build up the list of paths to pass to rustc -L
+ * 5. Call `cargo-rustc` with the results of the resolver zipped together with the results of the `get`
+ *    a. Topologically sort the dependencies
+ *    b. Compile each dependency in order, passing in the -L's pointing at each previously compiled dependency
+ */
+
+use std;
+use std::vec::Vec;
+use serialize::{Decodable};
+use hammer::{FlagDecoder,FlagConfig,FlagConfiguration,HammerError};
+use std::io;
+use std::io::BufReader;
+use std::io::process::{Process,ProcessExit,ProcessOutput,InheritFd,ProcessConfig};
+use {ToCargoError,CargoResult};
+
+#[deriving(Decodable)]
+struct Options {
+    manifest_path: ~str
+}
+
+impl FlagConfig for Options {
+    fn config(_: Option<Options>, c: FlagConfiguration) -> FlagConfiguration { c }
+}
+
+pub fn compile() -> CargoResult<()> {
+    let options = try!(flags::<Options>());
+    let manifest_bytes = try!(read_manifest(options.manifest_path).to_cargo_error(~"Could not read manifest", 1));
+
+    call_rustc(~BufReader::new(manifest_bytes.as_slice()))
+}
+
+fn flags<T: FlagConfig + Decodable<FlagDecoder, HammerError>>() -> CargoResult<T> {
+    let mut decoder = FlagDecoder::new::<T>(std::os::args().tail());
+    Decodable::decode(&mut decoder).to_cargo_error(|e: HammerError| e.message, 1)
+}
+
+fn read_manifest(manifest_path: &str) -> CargoResult<Vec<u8>> {
+    Ok((try!(exec_with_output("cargo-read-manifest", [~"--manifest-path", manifest_path.to_owned()], None))).output)
+}
+
+fn call_rustc(mut manifest_data: ~Reader:) -> CargoResult<()> {
+    let data: &mut Reader = manifest_data;
+    try!(exec_tty("cargo-rustc", [], Some(data)));
+    Ok(())
+}
+
+fn exec_with_output(program: &str, args: &[~str], input: Option<&mut Reader>) -> CargoResult<ProcessOutput> {
+    Ok((try!(exec(program, args, input, |_| {}))).wait_with_output())
+}
+
+fn exec_tty(program: &str, args: &[~str], input: Option<&mut Reader>) -> CargoResult<ProcessExit> {
+    Ok((try!(exec(program, args, input, |config| {
+        config.stdout = InheritFd(1);
+        config.stderr = InheritFd(2);
+    }))).wait())
+}
+
+fn exec(program: &str, args: &[~str], input: Option<&mut Reader>, configurator: |&mut ProcessConfig|) -> CargoResult<Process> {
+    let mut config = ProcessConfig::new();
+    config.program = program;
+    config.args = args;
+    configurator(&mut config);
+
+    println!("Executing {} {}", program, args);
+
+    let mut process = try!(Process::configure(config).to_cargo_error(~"Could not configure process", 1));
+
+    input.map(|mut reader| io::util::copy(&mut reader, process.stdin.get_mut_ref()));
+
+    Ok(process)
+}
+
diff --git a/src/cargo/ops/cargo_read_manifest.rs b/src/cargo/ops/cargo_read_manifest.rs
new file mode 100644 (file)
index 0000000..d777eae
--- /dev/null
@@ -0,0 +1,90 @@
+use toml;
+use hammer::FlagConfig;
+use serialize::Decoder;
+use toml::from_toml;
+use {CargoResult,ToCargoError,core};
+use std::path::Path;
+use collections::HashMap;
+use core::package::NameVer;
+use core::dependency::Dependency;
+
+#[deriving(Decodable,Encodable,Eq,Clone)]
+struct SerializedManifest {
+    project: ~core::Project,
+    lib: Option<~[SerializedLibTarget]>,
+    bin: Option<~[SerializedExecTarget]>,
+    dependencies: HashMap<~str, ~str>
+}
+
+#[deriving(Decodable,Encodable,Eq,Clone)]
+pub struct SerializedTarget {
+    name: ~str,
+    path: Option<~str>
+}
+
+pub type SerializedLibTarget = SerializedTarget;
+pub type SerializedExecTarget = SerializedTarget;
+
+
+#[deriving(Decodable,Eq,Clone,Ord)]
+pub struct ReadManifestFlags {
+    manifest_path: ~str
+}
+
+impl FlagConfig for ReadManifestFlags {}
+
+pub fn read_manifest(manifest_path: &str) -> CargoResult<core::Manifest> {
+    match execute(ReadManifestFlags { manifest_path: manifest_path.to_owned() }) {
+        Ok(manifest) => Ok(manifest.unwrap()),
+        Err(e) => Err(e)
+    }
+}
+
+pub fn execute(flags: ReadManifestFlags) -> CargoResult<Option<core::Manifest>> {
+    let manifest_path = flags.manifest_path;
+    let root = try!(toml::parse_from_file(manifest_path.clone()).to_cargo_error(format!("Couldn't parse Toml file: {}", manifest_path), 1));
+
+    let toml_manifest = try!(from_toml::<SerializedManifest>(root.clone()).to_cargo_error(|e: toml::Error| format!("Couldn't parse Toml file: {:?}", e), 1));
+
+    let (lib, bin) = normalize(&toml_manifest.lib, &toml_manifest.bin);
+
+    let SerializedManifest { project, dependencies, .. } = toml_manifest;
+
+    Ok(Some(core::Manifest {
+        root: try!(Path::new(manifest_path.clone()).dirname_str().to_cargo_error(format!("Could not get dirname from {}", manifest_path), 1)).to_owned(),
+        project: project,
+        lib: lib,
+        bin: bin,
+        dependencies: dependencies.iter().map(|(k,v)| NameVer::new(k.clone(),v.clone())).collect()
+    }))
+}
+
+fn normalize(lib: &Option<~[SerializedLibTarget]>, bin: &Option<~[SerializedExecTarget]>) -> (~[core::LibTarget], ~[core::ExecTarget]) {
+    fn lib_targets(libs: &[SerializedLibTarget]) -> ~[core::LibTarget] {
+        let l = &libs[0];
+        let path = l.path.clone().unwrap_or_else(|| format!("src/{}.rs", l.name));
+        ~[core::LibTarget { path: path, name: l.name.clone() }]
+    }
+
+    fn bin_targets(bins: &[SerializedExecTarget], default: |&SerializedExecTarget| -> ~str) -> ~[core::ExecTarget] {
+        bins.iter().map(|bin| {
+            let path = bin.path.clone().unwrap_or_else(|| default(bin));
+            core::ExecTarget { path: path, name: bin.name.clone() }
+        }).collect()
+    }
+
+    match (lib, bin) {
+        (&Some(ref libs), &Some(ref bins)) => {
+            (lib_targets(libs.as_slice()), bin_targets(bins.as_slice(), |bin| format!("src/bin/{}.rs", bin.name)))
+        },
+        (&Some(ref libs), &None) => {
+            (lib_targets(libs.as_slice()), ~[])
+        },
+        (&None, &Some(ref bins)) => {
+            (~[], bin_targets(bins.as_slice(), |bin| format!("src/{}.rs", bin.name)))
+        },
+        (&None, &None) => {
+            (~[], ~[])
+        }
+    }
+}
diff --git a/src/cargo/ops/cargo_rustc.rs b/src/cargo/ops/cargo_rustc.rs
new file mode 100644 (file)
index 0000000..7a6021f
--- /dev/null
@@ -0,0 +1,60 @@
+use std;
+use std::os::args;
+use std::io;
+use std::io::process::{Process,ProcessConfig,InheritFd};
+use std::path::Path;
+use {CargoResult,CargoError,ToCargoError,NoFlags,core};
+
+/**
+    cargo-rustc -- ...args
+
+    Delegate ...args to actual rustc command
+*/
+
+pub fn execute(_: NoFlags, manifest: core::Manifest) -> CargoResult<Option<core::Manifest>> {
+    let core::Manifest { root, lib, bin, .. } = manifest;
+
+    let (crate_type, out_dir) = if lib.len() > 0 {
+        ( ~"lib", lib[0].path )
+    } else if bin.len() > 0 {
+        ( ~"bin", bin[0].path )
+    } else {
+        return Err(CargoError::new(~"bad manifest, no lib or bin specified", 1));
+    };
+
+    let root = Path::new(root);
+    let target = join(&root, ~"target");
+
+    let args = [
+        join(&root, out_dir),
+        ~"--out-dir", target,
+        ~"--crate-type", crate_type
+    ];
+
+    match io::fs::mkdir_recursive(&root.join("target"), io::UserRWX) {
+        Err(_) => fail!("Couldn't mkdir -p"),
+        Ok(val) => val
+    }
+
+    println!("Executing rustc {}", args.as_slice());
+
+    let mut config = ProcessConfig::new();
+    config.stdout = InheritFd(1);
+    config.stderr = InheritFd(2);
+    config.program = "rustc";
+    config.args = args.as_slice();
+
+    let mut p = try!(Process::configure(config).to_cargo_error(format!("Could not start process: rustc {}", args.as_slice()), 1));
+
+    let status = p.wait();
+
+    if status != std::io::process::ExitStatus(0) {
+        fail!("Failed to execute")
+    }
+
+    Ok(None)
+}
+
+fn join(path: &Path, part: ~str) -> ~str {
+    format!("{}", path.join(part).display())
+}
diff --git a/src/cargo/ops/mod.rs b/src/cargo/ops/mod.rs
new file mode 100644 (file)
index 0000000..93d60da
--- /dev/null
@@ -0,0 +1,4 @@
+pub mod path_source;
+pub mod cargo_compile;
+pub mod cargo_read_manifest;
+pub mod cargo_rustc;
diff --git a/src/cargo/ops/path_source.rs b/src/cargo/ops/path_source.rs
new file mode 100644 (file)
index 0000000..6654c0b
--- /dev/null
@@ -0,0 +1 @@
+struct PathSourceOp;
diff --git a/src/cargo/sources/mod.rs b/src/cargo/sources/mod.rs
new file mode 100644 (file)
index 0000000..1fb8cc5
--- /dev/null
@@ -0,0 +1 @@
+mod path;
diff --git a/src/cargo/sources/path.rs b/src/cargo/sources/path.rs
new file mode 100644 (file)
index 0000000..40ef4f2
--- /dev/null
@@ -0,0 +1,49 @@
+use core::source::{Source,PackagePath};
+use core::package::NameVer;
+use CargoResult;
+use ops::cargo_read_manifest::read_manifest;
+
+struct PathSource {
+    paths: Vec<Path>
+}
+
+impl PathSource {
+    pub fn new(paths: Vec<Path>) -> PathSource {
+        PathSource { paths: paths }
+    }
+
+    fn map<T>(&self, callback: |&Path| -> CargoResult<T>) -> CargoResult<Vec<T>> {
+        let mut ret = Vec::with_capacity(self.paths.len());
+
+        for path in self.paths.iter() {
+            ret.push(try!(callback(path)));
+        }
+
+        Ok(ret)
+    }
+}
+
+impl Source for PathSource {
+    fn update(&self) -> CargoResult<()> { Ok(()) }
+
+    fn list(&self) -> CargoResult<Vec<NameVer>> {
+        self.map(|path| {
+            let manifest = try!(read_manifest(path.as_str().unwrap()));
+            Ok(manifest.get_name_ver())
+        })
+    }
+
+    fn download(&self, name_ver: Vec<NameVer>)  -> CargoResult<()>{
+        Ok(())
+    }
+
+    fn get(&self, packages: Vec<NameVer>) -> CargoResult<Vec<PackagePath>> {
+        self.map(|path| {
+            let manifest = try!(read_manifest(path.as_str().unwrap()));
+            let name_ver = manifest.get_name_ver();
+            let path = manifest.get_path();
+
+            Ok(PackagePath::new(name_ver, path))
+        })
+    }
+}